#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>    // close()
#include <arpa/inet.h> // inet_pton()
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>

#define PORT 8080
#define BUFFER_SIZE 1024

void *handle_client(void *arg)
{
    // 获取arg空间的数据，拷贝出来
    int new_socket = *((int *)arg);
    // 释放外部开辟的空间
    free(arg);
    // 用来缓存接受信息
    char buffer[BUFFER_SIZE];
    while (1)
    {
        memset(buffer, 0, BUFFER_SIZE);
        //read_len是实际接受数据的长度
        int read_len = recv(new_socket, buffer, BUFFER_SIZE - 1,0);
        //网络出错
        if (read_len < 0)
        {
            perror("socket read :");
            close(new_socket);
            return NULL;
        }

        //对端关闭
        if (read_len == 0)
        {
            printf("client close\n");
            close(new_socket);
            return NULL;
        }

        buffer[read_len] = '\0';

        printf("recv client message: %s\n", buffer);

        char resp[1024] = {0};
        snprintf(resp, 1023, "server receive: %s", buffer);

        int write_len = send(new_socket, resp, strlen(resp), 0);
        if (write_len < 0)
        {
            perror("socket send");
            close(new_socket);
            return NULL;
        }

        if (write_len == 0)
        {
            printf("client close\n");
            close(new_socket);
            return NULL;
        }

        printf("server send msg %s success!\n", resp);
    }

    return NULL;
}

int main()
{
    // 1. 创建socket
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0)
    {
        perror("server socket create");
        exit(1);
    }   

    int opt = 1;
    //设置socket的属性，为地址可重用，就是服务器处于time-wait状态，重启也可以使用
    int set_res = setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    if(set_res < 0){
        perror("server setsockopt");
        close(server_fd);
        exit(1);
    }

    // 2. 绑定地址和端口
    struct sockaddr_in server_addr;
    //地址长度
    int server_len = sizeof(server_addr);
    //将地址信息全部初始化为0
    memset(&server_addr, 0, server_len);
    //设置通信的协议族为IPV4
    server_addr.sin_family = AF_INET;
    //设置端口号，htons是将主机字节序转换为网络字节序
    server_addr.sin_port = htons(PORT);
    //设置地址，INADDR_ANY是绑定所有网络接口
    server_addr.sin_addr.s_addr = INADDR_ANY;
    //绑定socket和服务器地址
    int res = bind(server_fd, (struct sockaddr *)&server_addr, server_len);
    if (res < 0)
    {
        perror("server bind");
        close(server_fd);
        exit(1);
    }

    // 3. 监听连接，设置监听队列为5
    res = listen(server_fd, 5);
    if (res < 0)
    {
        perror("server listen");
        close(server_fd);
        exit(1);
    }

    // 4. 接受连接，client_addr缓存客户端的ip信息
    struct sockaddr_in client_addr;
    int client_len = sizeof(client_addr);
    int new_socket;
    while (1)
    {
        //接受客户端连接
        new_socket = accept(server_fd, (struct sockaddr *)&client_addr, &client_len);
        if (new_socket < 0)
        {
            perror("server accept");
            close(server_fd);
            exit(1);
        }
   
        //打印客户端ip信息
        char ip_buffer[1024]={0};
        inet_ntop(AF_INET, &(client_addr.sin_addr), ip_buffer, 1024);
        printf("receive client connection, ip is %s\n", ip_buffer);

        pthread_t tid;
        //malloc申请堆空间，这样线程使用时安全的
        int *socket_id_p = (int *)malloc(sizeof(int));
        *socket_id_p = new_socket;
        //创建线程处理读写请求 
        int res = pthread_create(&tid, NULL, handle_client, socket_id_p);
        if (res)
        {
            free(socket_id_p);
            close(new_socket);
            continue;
        }
        //分离线程，主线程退出，子线程自动被系统回收而不会触发底层信号
        pthread_detach(tid);
    }

    // 6. 关闭socket
    close(server_fd);
}